
#ifndef __ZEPP_LIST_H_
#define __ZEPP_LIST_H_

#include <stdlib.h>

#define USE_MACRO_LIST 1
#define DEBUG 1

#if USE_MACRO_LIST
#define ZEPPLIST_HEAD(name, type)   \
    struct name {                   \
        struct type *head;          \
        struct type *tail;          \
        struct type *nil;           \
        int size;                   \
    }

#define ZEPPLIST_ENTRY(name, type)  \
    struct name {                   \
        struct type *next;          \
        struct type *prev;          \
    }

/**
 * how to use
 *
 * ZEPPLIST_HEAD(zepplist_head, zepplist_node);
 *
 * struct zepplist_node {
 *
 *     your data;
 *
 *     ZEPPLIST_ENTRY(, struct zepplist_node) list_next;
 * };
 *
 */

#define CREATE_ZEPPLIST_HEAD(list, head_type) do { \
    (list) = (struct head_type *)calloc(1, sizeof(struct head_type)); \
}while (0)

#define ZEPPLIST_FIRST(head_) ((head_)->head)
#define ZEPPLIST_LAST(head) ((head)->tail)
#define ZEPPLIST_NULL(head) ((head)-> nil)
#define ZEPPLIST_SIZE(head) ((head)->size)

#define ZEPPLIST_EMPTY(head_) ((head_)->head == (head_)->nil && (head_)->tail == (head_)->nil)

#define ZEPPLIST_NEXT(elm, field) ((elm)->field.next)
#define ZEPPLIST_PREV(elm, field) ((elm)->field.prev)

#if DEBUG
#include <stdio.h>
#define ZPPLIST_CHECK_HEAD(head, field) do { \
    if (ZEPPLIST_HEAD(head) != ZEPPLIST_NULL(head) && \
        ZEPPLIST_NEXT(ZEPPLIST_FIRST(head), field) != \
            ZEPLIST_NULL(head) && \
        ZEPPLIST_PREV(ZEPPLIST_FIRST(head), field) != \
            ZEPPLIST_NULL(head)) \
        printf("[ERROR] Bad list head %p, next and prev != NULL\n", (head));\
} while (0)

#define ZEPPLIST_CHECK_NEXT(head, elm, field) do { \
    if (ZEPPLIST_PREV(ZEPPLIST_NEXT(elm, field), field) != elm) \
        printf("[ERROR] Bad link elm %p next->prev != elm\n", (elm)); \
} while (0)

#define ZEPPLIST_CHECK_PREV(head, elm, field) do {\
    if (ZEPPLIST_NEXT(ZEPPLIST_PREV(elm, field), field) != elm) \
        printf("[ERROR] Bad link elm %p prev->next != elm\n", (elm)); \
}while (0)
#else
#define ZPPLIST_CHECK_HEAD(head, field)
#define ZEPPLIST_CHECK_NEXT(head, elm, field)
#define ZEPPLIST_CHECK_PREV(head, elm, field)
#endif


#define INIT_ZEPPLIST_HEAD(list, node_type, field) do {     \
    if ((list) == NULL)                                     \
        break;                                              \
    ZEPPLIST_NULL(list) = (struct node_type *)calloc(1, sizeof(struct node_type));\
    ZEPPLIST_FIRST(list) = ZEPPLIST_NULL(list);             \
    ZEPPLIST_LAST (list) = ZEPPLIST_NULL(list);             \
    ZEPPLIST_NEXT(ZEPPLIST_NULL(list), field) = ZEPPLIST_NULL(list);\
    ZEPPLIST_PREV(ZEPPLIST_NULL(list), field) = ZEPPLIST_NULL(list);\
} while(0)

#define ZEPPLIST_FOREACH(var, head, field)                  \
    for ((var) = ZEPPLIST_FIRST(head);                      \
        (var) != ZEPPLIST_NULL(head);                       \
        (var) = ZEPPLIST_NEXT(var, field))

// 允许在循环中修改链表
#define ZEPPLIST_FOREACH_SAFE(var, head, field, tvar)       \
    for ((var) = ZEPPLIST_FIRST(head);                      \
        (var) != ZEPPLIST_NULL(head) && ((tvar) = ZEPPLIST_NEXT(var, field), 1);    \
        (var) = (tvar))

#define ZEPPLIST_INSERT_AFTER(head, baseelm, elm, field) do {   \
    ZEPPLIST_CHECK_NEXT(head, baseelm, field); \
    ZEPPLIST_NEXT(elm, field) = ZEPPLIST_NEXT(baseelm, field);  \
    ZEPPLIST_PREV(elm, field) = baseelm;                    \
    ZEPPLIST_PREV(ZEPPLIST_NEXT(elm, field), field) = elm;  \
    ZEPPLIST_NEXT(baseelm, field) = elm;                    \
    ZEPPLIST_SIZE(head) ++;                                 \
} while (0)

#define ZEPPLIST_INSERT_BEFORE(head, baseelm, elm, field) do {  \
    ZEPPLIST_CHECK_PREV(head, baseelm, field); \
    ZEPPLIST_NEXT(elm, field) = baseelm;                    \
    ZEPPLIST_PREV(elm, field) = ZEPPLIST_PREV(baseelm, field);  \
    ZEPPLIST_NEXT(ZEPPLIST_PREV(elm, field), field) = elm;  \
    ZEPPLIST_PREV(baseelm, field) = elm;                    \
    ZEPPLIST_SIZE(head) ++;                                 \
} while (0)

#define ZEPPLIST_INSERT_HEAD(head, elm, field) do {         \
    ZEPPLIST_INSERT_BEFORE(head, ZEPPLIST_FIRST(head), elm, field); \
    ZEPPLIST_FIRST(head) = elm;                              \
    if (ZEPPLIST_LAST(head) == ZEPPLIST_NULL(head)) {       \
        ZEPPLIST_LAST(head) = elm;}                         \
} while(0)

#define ZEPPLIST_INSERT_TAIL(head, elm, field) do {         \
    ZEPPLIST_INSERT_AFTER(head, ZEPPLIST_LAST(head), elm, field);   \
    ZEPPLIST_LAST(head) = elm;                              \
    if (ZEPPLIST_FIRST(head) == ZEPPLIST_NULL(head)) {      \
        ZEPPLIST_FIRST(head) = elm;}                        \
} while (0)


#define ZEPPLIST_REMOVE(head, elm, field) do {              \
    ZEPPLIST_CHECK_PREV(head, elm, field); \
    ZEPPLIST_CHECK_NEXT(head, elm, field); \
    if (elm == ZEPPLIST_FIRST(head))                        \
        ZEPPLIST_FIRST(head) = ZEPPLIST_NEXT(elm, field);   \
    if (elm == ZEPPLIST_LAST(head))                         \
        ZEPPLIST_LAST(head) = ZEPPLIST_PREV(elm, field);    \
    ZEPPLIST_PREV(ZEPPLIST_NEXT(elm, field), field) = ZEPPLIST_PREV(elm, field);    \
    ZEPPLIST_NEXT(ZEPPLIST_PREV(elm, field), field) = ZEPPLIST_NEXT(elm, field);    \
    ZEPPLIST_SIZE(head) --; \
} while (0)


#define ZEPPLIST_SWAP_NODE(head, elm1, elm2, type, field) do {  \
    if (elm1 == elm2 || elm1 == ZEPPLIST_NULL(head) || elm2 == ZEPPLIST_NULL(head))\
        break;                                                  \
    struct type *elm1_prev = ZEPPLIST_PREV(elm1, field);        \
    struct type *elm1_next = ZEPPLIST_NEXT(elm1, field);        \
    struct type *elm2_prev = ZEPPLIST_PREV(eml2, field);        \
    struct type *elm2_next = ZEPPLIST_NEXT(elm2, field);        \
    if (elm1_next == elm2) {                                    \
        ZEPPLIST_NEXT(elm1, field) = elm2_next;                 \
        ZEPPLIST_PREV(elm1, field) = elm2;                      \
        ZEPPLIST_NEXT(elm2, field) = elm1;                      \
        ZEPPLIST_PREV(elm2, field) = elm1_prev;                 \
    } else if (elm2_next == elm1) {                             \
        ZEPPLIST_NEXT(elm2, field) = elm1_next;                 \
        ZEPPLIST_PREV(elm2, field) = elm1;                      \
        ZEPPLIST_NEXT(elm1, field) = elm2;                      \
        ZEPPLIST_PREV(elm1, field) = elm2_prev;                 \
    } else {                                                    \
        ZEPPLIST_NEXT(elm1, field) = elm2_next;                 \
        ZEPPLIST_PREV(elm1, field) = elm2_prev;                 \
        ZEPPLIST_NEXT(elm2, field) = elm1_next;                 \
        ZEPPLIST_PREV(elm2, field) = elm1_prev;                 \
    }                                                           \
    if (ZEPPLIST_PREV(elm1, field) != ZEPPLIST_NULL(head))      \
        ZEPPLIST_NEXT(ZEPPLIST_PREV(elm1, field), field) = elm1;\
    else                                                        \
        ZEPPLIST_HEAD(head) = elm1;                             \
    if (ZEPPLIST_NEXT(elm1, field) != ZEPPLIST_NULL(head))      \
        ZEPPLIST_PREV(ZEPPLIST_NEXT(elm1, field), field) = elm1;\
    else                                                        \
        ZEPPLIST_LAST(head) = elm1;                             \
    if (ZEPPLIST_PREV(elm2, field) != ZEPPLIST_NULL(head))      \
        ZEPPLIST_NEXT(ZEPPLIST_PREV(elm2, field), field) = elm2;\
    else                                                        \
        ZEPPLIST_HEAD(head) = elm2;                             \
    if (ZEPPLIST_NEXT(elm2, field) != ZEPPLIST_NULL(head))      \
        ZEPPLIST_PREV(ZEPPLIST_NEXT(elm2, field), field) = elm2;\
    else                                                        \
        ZEPPLIST_LAST(head) = elm2;                             \
}while (0)

#define ZEPPLIST_GET_BLOCK(head, index, pos, field) do {        \
    (pos) = ZEPPLIST_FIRST(head);                               \
    while ((index) -- && ZEPPLIST_NEXT(pos, field))             \
        (pos) = ZEPPLIST_NEXT(pos, field);                      \
}while(0)

#define ZEPPLIST_PRINT_NODE(node, field) do { \
    printf("prev: %p, node  : %p, next:%p\n",  \
                ZEPPLIST_PREV(node, field), \
                node, ZEPPLIST_NEXT(node, field)); \
} while (0)

#define ZEPPLIST_PRINT_LIST(head, node_type, field) do { \
    node_type *__pos;int __count = 0; \
    printf("list size: %d\n", ZEPPLIST_SIZE(head)); \
    printf("prev: %p,  NULL  : %p, next:%p\n",  \
            ZEPPLIST_PREV(ZEPPLIST_NULL(head), field), \
            ZEPPLIST_NULL(head), \
            ZEPPLIST_NEXT(ZEPPLIST_NULL(head), field)); \
    ZEPPLIST_FOREACH(__pos, head, field)\
        printf("prev: %p, node[%d]: %p, next:%p\n",  \
                ZEPPLIST_PREV(__pos, field), __count ++, \
                __pos, ZEPPLIST_NEXT(__pos, field)); \
} while (0)

#endif

#define Elemtype struct list_node
#define Datatype int
#define Datasize 16

struct list_head {
    Elemtype *head;
    Elemtype *tail;
    int size;

    Elemtype *nil; // 边界空结点
};

struct list_node {
    Datatype *datas;

    Elemtype *next;
    Elemtype *prev;
};

#define list_foreach(start, end, var) \
    for (Elemtype *(var) = (start); (var) != (end); (var) = (var)->next) \

void init_list_head(struct list_head *list);
struct list_head *create_list_head();

struct list_node *create_list_node();
void list_node_data_alloc(struct list_node *node);

void destroy_list(struct list_head *list);
void destroy_list_head(struct list_head *list);

void destroy_list_node(struct list_node *node);
void list_node_data_destroy(struct list_node *node);

void insert_list_after(struct list_head *list, struct list_node *base, struct list_node *after);
void insert_list_before(struct list_head *list, struct list_node *base, struct list_node *before);
void insert_list_head(struct list_head *list, struct list_node *node);
void insert_list_tail(struct list_head *list, struct list_node *node);

void list_remove(struct list_head *list, struct list_node *node);

void list_swap_node(struct list_head *list, struct list_node *a, struct list_node *b);
void list_swap_data(struct list_head *list, Datatype *a, Datatype *b);

struct list_node *get_index_block(struct list_head *list, int index);
Datatype *get_index(struct list_head *list, int index);

#endif // __ZEPP_LIST_H_





